package com.google.code.securityflow.ast

import util.Random
import com.google.code.securityflow.graphviz.{GraphvizTreeLeaf, GraphvizTree, GraphvizTreeNode}

abstract sealed class Expression(id: Int, location: SourceLocation) extends Node(id, location) {

  def canonicalName: String;

  def toGraphviz: GraphvizTree = {
    this match {
      case exp@IntegerLiteralExpression(id, value, _, _) =>
        GraphvizTreeNode(id, exp.canonicalName, List(GraphvizTreeLeaf(Random.nextInt(Int.MaxValue), value.toString)));

      case exp@ObjectLiteralExpression(id, _) =>
        GraphvizTreeNode(id, exp.canonicalName, List(GraphvizTreeLeaf(Random.nextInt(Int.MaxValue), "\\{\\}")));

      case exp@FunctionLiteralExpression(id, body, _) =>
        GraphvizTreeNode(id, exp.canonicalName, List(body.toGraphviz));

      case exp@BinaryExpression(id, operator, left, right, _) =>
        GraphvizTreeNode(id, exp.canonicalName, List(left.toGraphviz, right.toGraphviz));

      case exp@SimplePropertyAccessExpression(id, name, _) =>
        GraphvizTreeNode(id, exp.canonicalName, List(GraphvizTreeLeaf(Random.nextInt(Int.MaxValue), name)));

      case exp@QualifiedPropertyAccessExpression(id, property, name, _) =>
        GraphvizTreeNode(id, exp.canonicalName, List(property.toGraphviz, GraphvizTreeLeaf(Random.nextInt(Int.MaxValue), name)));
    }
  }
}

abstract sealed class PropertyAccessExpression(id: Int, location: SourceLocation) extends Expression(id, location) {

}

case class IntegerLiteralExpression(id: Int, value: Int, high: Boolean, location: SourceLocation) extends Expression(id, location) {
  override def canonicalName = "IntegerLiteralExp[L" + location.lineNumber + ":" + location.position + "]";
}

case class ObjectLiteralExpression(id: Int, location: SourceLocation) extends Expression(id, location) {
  override def canonicalName = "ObjectLiteralExp[L" + location.lineNumber + ":" + location.position + "]";
}

case class FunctionLiteralExpression(id: Int, body: Block, location: SourceLocation) extends Expression(id, location) {
  override def canonicalName = "FunctionLiteral[L" + location.lineNumber + ":" + location.position + "]";
}

case class BinaryExpression(id: Int, operator: Operator, left: Expression, right: Expression, location: SourceLocation) extends Expression(id, location) {
  override def canonicalName = "BinaryExp" + operator.canonicalName + "[L" + location.lineNumber + ":" + location.position + "]";
}

case class SimplePropertyAccessExpression(id: Int, name: String, location: SourceLocation) extends PropertyAccessExpression(id, location) {
  override def canonicalName = "SimplePropAccExp[L" + location.lineNumber + ":" + location.position + "]";
}

case class QualifiedPropertyAccessExpression(id: Int, base: PropertyAccessExpression, name: String, location: SourceLocation) extends PropertyAccessExpression(id, location) {
  override def canonicalName = "QualifiedPropAccExp[L" + location.lineNumber + ":" + location.position + "]";
}
